#include "NVMeBasicContext.hpp"

#include "NVMeCommon.hpp"

#include <endian.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include <FileHandle.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>

#include <cassert>
#include <cerrno>
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <system_error>
#include <thread>

extern "C"
{
#include <i2c/smbus.h>
#include <linux/i2c-dev.h>
}

/*
 * NVMe-MI Basic Management Command
 *
 * https://nvmexpress.org/wp-content/uploads/NVMe_Management_-_Technical_Note_on_Basic_Management_Command.pdf
 */

static constexpr const uint8_t basicCommandAddr = 0x6a;
static constexpr const uint8_t vpdCommandAddr = 0x53;

static constexpr const uint8_t basicCommand0 = 0;
static constexpr const uint8_t basicCommand8 = 8;
static constexpr const uint8_t basicCommand32 = 32;

static constexpr const uint8_t basicCommand0Length = 8;
static constexpr const uint8_t basicCommand8Length = 23;
static constexpr const uint8_t basicCommand32Length = 32;
static constexpr const uint16_t vpdCommandLength = 256;

static constexpr const uint8_t serialOffsetStart = 3;
static constexpr const uint8_t serialOffsetEnd = 23;

static constexpr const uint8_t fwOffsetStartAt1 = 1;
static constexpr const uint8_t fwOffsetStartAt7 = 7;
static constexpr const uint8_t fwOffsetEndAt9 = 9;
static constexpr const uint8_t fwOffsetEndAt15 = 15;

static constexpr const uint8_t modulOffsetStartAt25 = 25;
static constexpr const uint8_t modulOffsetStartAt46 = 46;
static constexpr const uint8_t modulOffsetEndAt65 = 65;
static constexpr const uint8_t modulOffsetEndAt86 = 86;

static constexpr const int temperatureSensorFailure = 0x81;
static constexpr const int percentageDriveLifeUsed = 0;
static constexpr const int smartWarningInitNone = 0xFF;
static constexpr const int statusFlagsInitDefault = 0x03;

static constexpr int driveLifeUsedThread = 10;//drivelifeused参数小于10时告警
static constexpr std::string TestFilePath = "/var/nvmelife";//test file存放drivelifeused测试值

static std::map<std::string, std::string> mapVendor = {
    {"0x8086", "Intel"},     {"0x8680", "Intel"},    {"0x144d", "Samsung"},
    {"0x4d14", "Samsung"},   {"0x1bd4", "Otrd"},   {"0xd41b", "Otrd"},
    {"0x1c5f", "MemBlaze"},  {"0x5f1c", "MemBlaze"}, {"0x1344", "Micron"},
    {"0x4413", "Micron"},    {"0x1e0f", "Kioxia"},   {"0x0f1e", "Kioxia"},
    {"0x1d78", "Dera"},      {"0x781d", "Dera"},     {"0xcc53", "ScaleFlux"},
    {"0xcc53", "ScaleFlux"}, {"0x1b96", "WD"},       {"0x961b", "WD"}};

static std::map<int, bool> basicNVMeStateMaps;
static std::map<int, bool> vpdNVMeStateMaps;
static std::map<int, NVMeData> nvmeDataMaps;

static std::shared_ptr<std::array<uint8_t, 4>> encodeBasicQuery(int bus)
{
    if (bus < 0)
    {
        throw std::domain_error("Invalid bus argument");
    }

    /* bus */
    uint32_t busle = htole32(static_cast<uint32_t>(bus));
    auto command = std::make_shared<std::array<uint8_t, sizeof(busle)>>();
    memcpy(command->data(), &busle, sizeof(busle));

    return command;
}

static void decodeBasicQuery(const std::array<uint8_t, 4>& req, int& bus)
{
    uint32_t busle = 0;

    memcpy(&busle, req.data(), sizeof(busle));
    bus = le32toh(busle);
}

/** @brief 该函数用来初始化NVMe参数的信息
 *  @param[in] nvmeData: 未初始化的NVMe参数信息
 *  @param[out] nvmeData: 初始化后的NVMe参数信息
 *  @note 0. NVMe在位代码流程才能到此，所以赋值true
 *        1. interface和media类型，参照X86写死
 *        2. 其他值参照SPEC赋初值或者置空
 */
void initNVMeData(NVMeData* nvmeData)
{
    if (nvmeData == nullptr)
    {
        return;
    }

    nvmeData->present = true;
    nvmeData->vendor = "";
    nvmeData->serialNumber = "";
    nvmeData->modelNumber = "";
    nvmeData->firmwareVersion = "";
    nvmeData->interfaceType = "PCIE";
    nvmeData->mediaType = "SSD";
    nvmeData->smartWarnings = static_cast<int8_t>(smartWarningInitNone);
    nvmeData->statusFlags = static_cast<int8_t>(statusFlagsInitDefault);
    nvmeData->driveLifeUsed = static_cast<int8_t>(percentageDriveLifeUsed);
    nvmeData->sensorValue = static_cast<int8_t>(temperatureSensorFailure);
    nvmeData->wcTemp = 0;
}

/** @brief 检测NVME的driveLifeUsed参数
 ** @brief  当参数小于30时（默认值255的10%）将smartWarnings值置为0x4，即产生DegradesFault（可靠性降低）的日志
 *  @param[in] u8lifeused: NVME的driveLifeUsed参数
 *  @param[out] pu8smartWarn: NVMe的smartWarnings参数
 */
void checkNVMeLifeUsed(uint8_t u8lifeused, uint8_t *pu8smartWarn)
{
    if (pu8smartWarn == nullptr)
    {
        return;
    }
    if (u8lifeused < driveLifeUsedThread)
    {
        *pu8smartWarn = degradesFaultMask;
    }
}

/** @brief 测试NVME的driveLifeUsed参数（模拟测试接口）
 *   @brief  正常情况下NVME的driveLifeUsed数值不会低于30，这里使用该接口模拟测试，测试时手动向/var/nvmelife文件中写数值，该接口读取数值判断
 *   @param[in] u8lifeused: NVME的driveLifeUsed参数
 *   @param[out] u8smartWarn: NVMe的smartWarnings参数
 */
uint8_t testNVMeLifeUsed(uint8_t u8lifeused,  uint8_t u8smartWarn, const std::string& filePath)
{
    uint8_t u8Value = 0x00;
    if (!std::filesystem::exits(filePath))
    {
        return u8smartWarn;
    }

    std::ifstream file(filePath);
    if (!file.is_open())
    {
        return u8smartWarn;
    }

    if (!(file >> u8Value))
    {
        return u8smartWarn;
    }
    file.close();

    return u8Value;
}


int parseNVMeBasicInfo(uint8_t commandNumber, uint8_t* respData,
                       NVMeData* nvmeData)
{
    if (respData == nullptr || nvmeData == nullptr)
    {
        return -1;
    }

    if (commandNumber == basicCommand0)
    {
        nvmeData->statusFlags = static_cast<uint8_t>(respData[1]);
        nvmeData->smartWarnings = static_cast<uint8_t>(respData[2]);
        nvmeData->driveLifeUsed = static_cast<uint8_t>(respData[4]);
        nvmeData->sensorValue = static_cast<int8_t>(respData[3]);
        nvmeData->wcTemp = static_cast<int8_t>(respData[5]);
        
        //test nvme life used参数
        testNVMeLifeUsed(nvmeData->driveLifeUsed,  nvmeData->smartWarnings, const std::string& TestFilePath);
       
       //check nvme life used参数
        checkNVMeLifeUsed(nvmeData->driveLifeUsed, &nvmeData->smartWarnings);
    }
    else if (commandNumber == basicCommand8)
    {
        // 解析出NVMe的厂商
        nvmeData->vendor = "0x" + intToHex(respData[1]) + intToHex(respData[2]);

        if (mapVendor.contains(nvmeData->vendor))
        {
            nvmeData->vendor = mapVendor.at(nvmeData->vendor);
        }

        // 解析出NVMe的序列号
        std::string serialNumberBuff = "";
        for (int offset = serialOffsetStart; offset < serialOffsetEnd; offset++)
        {
            // Only accept digits/letters/punctuation characters.
            if (respData[offset] >= '!' && respData[offset] <= '~')
            {
                nvmeData->serialNumber += static_cast<char>(respData[offset]);
            }
        }
    }
    else if (commandNumber == basicCommand32)
    {
        //解析出NVMe的版本号
        if (nvmeData->vendor == "Intel" || nvmeData->vendor == "Otrd" ||
            nvmeData->vendor == "MemBlaze" || nvmeData->vendor == "Micron" ||
            nvmeData->vendor == "Dera")
        {
            for (int offset = fwOffsetStartAt7; offset < fwOffsetEndAt15;
                 offset++)
            {
                if (respData[offset] >= '!' && respData[offset] <= '~')
                {
                    nvmeData->firmwareVersion +=
                        static_cast<char>(respData[offset]);
                }
            }
        }
        else if (nvmeData->vendor == "Samsung")
        {
            for (int offset = fwOffsetStartAt1; offset < fwOffsetEndAt9;
                 offset++)
            {
                if (respData[offset] >= '!' && respData[offset] <= '~')
                {
                    nvmeData->firmwareVersion +=
                        static_cast<char>(respData[offset]);
                }
            }
        }
        if (nvmeData->firmwareVersion == "")
        {
            nvmeData->firmwareVersion = "N/A";
        }
    }

    return 0;
}

int parseStandardVPDInfo(uint8_t* fruDataSrc, uint8_t fruType, uint8_t fruItem,
                         char* bufferString, int bufferSrtingMaxSize)
{
    int retval = 0;
    int offset = 0;
    FruCommonHeaderT fruHeader;
    std::array<uint8_t, vpdCommandLength> fruData{};
    uint8_t counter = 0;
    uint8_t typecode = 0;
    uint8_t dataLen = 0;

    if ((fruDataSrc == nullptr) || (bufferString == nullptr))
    {
        return -1;
    }
    memcpy(fruData.data(), fruDataSrc, vpdCommandLength);
    memcpy(&fruHeader, fruData.data(), sizeof(FruCommonHeaderT));

    if (fruHeader.CommonHeaderFormatVersion != 0x01)
    {
        std::cerr << "FRU version is not 0x01\n";
        return -1;
    }
    switch (fruType) //根据FRU类型定位FRU位置
    {
        case INTERNAL_USE_AREA: // EEPROM_FRU_INTERNAL:
            offset = fruHeader.InternalUseAreaStartOffset * 8 + 3;
            break;
        case CHASSIS_INFO_AREA: // EEPROM_FRU_CHASSIS:
            offset = fruHeader.ChassisInfoAreaStartOffset * 8 + 3;
            break;
        case BOARD_INFO_AREA: // EEPROM_FRU_BOARD:
            offset = fruHeader.BoardInfoAreaStartOffset * 8 + 6;
            if (fruItem < EEPROM_FRU_BOARD_MANUFACTURER) // review:判断
            {
                return -1;
            }
            for (counter = 0;
                 counter < (fruItem - EEPROM_FRU_BOARD_MANUFACTURER);
                 counter++) //跳过前面的数据项
            {
                offset += (fruData[offset] & 0x3F); // bits 0:5 length
                offset++;
            }
            break;
        case PRODUCT_INFO_AREA: // EEPROM_FRU_PRODUCT:
            offset = fruHeader.ProductInfoAreaStartOffset * 8 + 3;
            if (fruItem < EEPROM_FRU_PRODUCT_MANUFACTURER) // review:判断
            {
                return -1;
            }
            for (counter = 0;
                 counter < (fruItem - EEPROM_FRU_PRODUCT_MANUFACTURER);
                 counter++) //跳过前面的数据项
            {
                offset += (fruData[offset] & 0x3F); // bits 0:5 length
                offset++;
            }
            break;
        case MULTI_RECORD_AREA: // EEPROM_FRU_MULTI:
            offset = fruHeader.MultiRecordAreaStartOffset * 8 + 3;
            break;
        default:
            offset = 0;
            break;
    }
    if (offset >= vpdCommandLength) // review offset判断
    {
        return -1;
    }
    typecode = ((fruData[offset] & 0xC0) >> 6); // bit 6:7 contain format
    if (typecode == 0)
    { // binary/unspecified    hex dump ->2x length
        dataLen = (fruData[offset] & 0x3F);
        dataLen <<= 1;
    }
    else if ((typecode == 1) || (typecode == 3))
    { // 11b: 8 bit ASCII   01b: BCD plus
        dataLen = (fruData[offset] & 0x3F);
    }
    else if (typecode == 2)
    { // 6-bit  ASCII       4chars per group of 1-3 bytes
        dataLen = ((((fruData[offset] & 0x3F) + 2) * 4 / 3) & ~3);
    }
    else
    {
        return -1;
    }
    offset++;
    if (dataLen <= bufferSrtingMaxSize)
    {
        memcpy(bufferString, &fruData[offset], dataLen);
    }
    else
    {
        memcpy(bufferString, &fruData[offset], bufferSrtingMaxSize);
    }
    return retval;
}

int parseNVMeVPDInfo(uint8_t* respData, NVMeData* nvmeData)
{
    if (respData == nullptr || nvmeData == nullptr)
    {
        return -1;
    }

    /* 0. 通过I2C读取的VPD信息可以获取modelnumber */
    std::string modulBuff = "";
    if (nvmeData->vendor == "Samsung" || nvmeData->vendor == "MemBlaze" ||
        nvmeData->vendor == "Dera" ||
        (nvmeData->vendor == "Otrd" && respData[1] == 'B'))
    {
        if (respData[1] == 0xff)
        {
            modulBuff = "N/A";
        }
        else
        {
            std::array<char, 32> productName{};
            memcpy(productName.data(), &respData[21], 32);
            if (strncmp(productName.data(), "PM9A3", sizeof("PM9A3")) == 0)
            {
                for (int offset = modulOffsetStartAt46;
                     offset < modulOffsetEndAt86; offset++)
                {
                    modulBuff += static_cast<char>(respData[offset]);
                }
            }
            else
            {
                for (int offset = modulOffsetStartAt25;
                     offset < modulOffsetEndAt65; offset++)
                {
                    modulBuff += static_cast<char>(respData[offset]);
                }
            }

            for (int offset = modulBuff.size() - 1; offset > -1; offset--)
            {
                if (modulBuff[offset] < '!' || modulBuff[offset] > '~')
                {
                    modulBuff.erase(offset, 1);
                }
                else
                {
                    break;
                }
            }
        }

        if (modulBuff != "")
        {
            nvmeData->modelNumber = modulBuff;
        }
    }
    else
    {
        parseStandardVPDInfo(respData, PRODUCT_INFO_AREA,
                             EEPROM_FRU_PRODUCT_PARTNUM,
                             (char*)nvmeData->modelNumber.c_str(), 65);
    }

    return 0;
}

/** @brief 获取NVMe Basic Command信息
 *  @param[in] bus: NVMe设备对应的bus信息，跟dts一致
 *  @param[out] resp: 从SMBus获取的NVMe信息
 *  @note 0. 对于NVMe Basic信息来讲，走SMBus获取的信息，需要分3次获取
 */
int getNVmeBasicComInfo(int bus, std::vector<uint8_t>& resp)
{
    int32_t size = 0;
    std::vector<uint8_t> respDataCommand0{};
    std::vector<uint8_t> respDataCommand8{};
    std::vector<uint8_t> respDataCommand32{};

    /* 0. 获取目标设备 */
    std::filesystem::path devpath = "/dev/i2c-" + std::to_string(bus);
    if (!std::filesystem::exists(devpath))
    {
        std::cerr << "Failed to open file: " << std::string(devpath)
                  << ". Please check the nvme configuration file.\n";
        return -errno;
    }
    FileHandle fileHandle(devpath);

    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
    if (::ioctl(fileHandle.handle(), I2C_SLAVE, basicCommandAddr) == -1)
    {
        std::cerr << "Failed to configure device address 0x6a for bus "
                  << std::dec << bus << ": " << strerror(errno) << "\n";

        return -errno;
    }

    /* 1. 依据NVMe通用规范，发送Command0获取信息：该命令获取的主要是动态信息 */
    respDataCommand0.resize(UINT8_MAX + 1);
    size = i2c_smbus_read_i2c_block_data(fileHandle.handle(), basicCommand0,
                                         basicCommand0Length,
                                         respDataCommand0.data());
    if (size < 0)
    {
        std::cerr << "Failed to get nvme basic command 0 info for bus "
                  << std::dec << bus << ": " << strerror(errno) << "\n";

        return size;
    }
    respDataCommand0.resize(size);
    resp.resize(0);
    resp.insert(resp.end(), respDataCommand0.begin(), respDataCommand0.end());

    if (basicNVMeStateMaps[bus] == false)
    {
        /* 2. 依据NVMe通用规范，发送Command8获取信息：该命令获取的是VenID和PSN
         */
        respDataCommand8.resize(UINT8_MAX + 1);
        size = i2c_smbus_read_i2c_block_data(fileHandle.handle(), basicCommand8,
                                             basicCommand8Length,
                                             respDataCommand8.data());
        if (size < 0)
        {
            std::cerr << "Failed to get nvme basic command 8 info for bus "
                      << std::dec << bus << ": " << strerror(errno) << "\n";

            return size;
        }
        respDataCommand8.resize(size);
        resp.insert(resp.end(), respDataCommand8.begin(),
                    respDataCommand8.end());

        /* 3. 依据NVMe通用规范，发送Command32获取信息：该命令获取的主要是FWVer
         */
        respDataCommand32.resize(UINT8_MAX + 1);
        size = i2c_smbus_read_i2c_block_data(
            fileHandle.handle(), basicCommand32, basicCommand32Length,
            respDataCommand32.data());
        if (size < 0)
        {
            std::cerr << "Failed to get nvme basic command 32 info for bus "
                      << std::dec << bus << ": " << strerror(errno) << "\n";

            return size;
        }
        respDataCommand32.resize(size);
        resp.insert(resp.end(), respDataCommand32.begin(),
                    respDataCommand32.end());
    }

    return 0;
}

/** @brief 获取NVMe VPD信息
 *  @param[in] bus: NVMe设备对应的bus信息，跟dts一致
 *  @param[out] resp: 从I2C获取的NVMe信息
 *  @note 0. 对于NVMe VPD信息来讲，走I2C获取的信息
 */
int getNVmeVPDInfo(int bus, std::vector<uint8_t>& resp)
{
    int32_t size = 0;
    uint8_t txData = 0;
    std::vector<uint8_t> respDataComVPD{};

    /* 0. 获取目标设备 */
    std::filesystem::path devpath = "/dev/i2c-" + std::to_string(bus);
    if (!std::filesystem::exists(devpath))
    {
        std::cerr << "Failed to open file: " << std::string(devpath)
                  << ". Please check the nvme configuration file.\n";
        return -errno;
    }
    FileHandle fileHandle(devpath);
    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg)
    if (::ioctl(fileHandle.handle(), I2C_SLAVE, vpdCommandAddr) == -1)
    {
        std::cerr << "Failed to configure device address 0x53 for bus "
                  << std::dec << bus << ": " << strerror(errno) << "\n";

        return -errno;
    }

    /* 1. 依据厂商规范，发送指令获取VPD信息：该命令获取的主要是动态信息 */
    respDataComVPD.resize(vpdCommandLength);
    size =
        i2cReadAfterWrite(fileHandle.handle(), vpdCommandAddr, sizeof(txData),
                          &txData, (vpdCommandLength), respDataComVPD.data());
    if (size < 0)
    {
        std::cerr << "Failed to get nvme vpd info for bus " << std::dec << bus
                  << ": " << strerror(errno) << "\n";
        return size;
    }

    resp.insert(resp.end(), respDataComVPD.begin(), respDataComVPD.end());

    return 0;
}

/** @brief 该函数用来获取NVMe的静态信息和动态信息，依赖Basic指令和VPD指令
 *  @param[in] bus: 当前设备的总线信息
 *  @param[out] resp: 需要向外传递的NVMe信息
 *  @note 0. NVMe的Basic指令是NVMe的标准规范，是需要各个厂商默认遵守的:
 *           Basic Command的地址默认0x6a;
 *           Basic Command 0 和 Basic Command 8是标准规定；
 *           Basic Command 32+由各个厂商特定.
 *        1. NVMe的VPD指令可以获取其他信息，各个厂商不太一致:
 *           VPD Command的地址默认0x53.
 *        2. 部分厂商比较特殊，可能会和上面的1/2有一些不同.
 */
static ssize_t execBasicQuery(int bus, std::vector<uint8_t>& resp)
{
    int ret = 0;

    ret = getNVmeBasicComInfo(bus, resp);
    if (ret < 0)
    {
        return ret;
    }

    if (vpdNVMeStateMaps[bus] == false)
    {
        ret = getNVmeVPDInfo(bus, resp);
        if (ret < 0)
        {
            return ret;
        }
    }

    return resp.size();
}

static ssize_t processBasicQueryStream(FileHandle& in, FileHandle& out)
{
    std::vector<uint8_t> resp{};
    ssize_t rc = 0;

    while (true)
    {
        uint16_t len = 0;
        int bus = 0;

        /* bus */
        std::array<uint8_t, sizeof(uint32_t)> req{};

        /* Read the command parameters */
        ssize_t rc = ::read(in.handle(), req.data(), req.size());
        if (rc != static_cast<ssize_t>(req.size()))
        {
            std::cerr << "Failed to read request from in descriptor "
                      << strerror(errno) << "\n";
            if (rc)
            {
                return -errno;
            }
            return -EIO;
        }

        decodeBasicQuery(req, bus);

        /* Execute the query */
        rc = execBasicQuery(bus, resp);

        /* Bounds check the response. it is normal to exceed 256 */
        if (rc < 0)
        {
            len = 0;
        }
        else
        {
            len = rc;
        }

        /* Write out the response length */
        rc = ::write(out.handle(), &len, sizeof(len));
        if (rc != sizeof(len))
        {
            std::cerr << "Failed to write block (" << std::dec << len
                      << ") length to out descriptor: "
                      << strerror(static_cast<int>(-rc)) << "\n";
            if (rc)
            {
                return -errno;
            }
            return -EIO;
        }

        /* Write out the response data */
        std::vector<uint8_t>::iterator cursor = resp.begin();
        while (cursor != resp.end())
        {
            size_t lenRemaining = std::distance(cursor, resp.end());
            ssize_t egress = ::write(out.handle(), &(*cursor), lenRemaining);
            if (egress == -1)
            {
                std::cerr << "Failed to write block data of length " << std::dec
                          << lenRemaining << " to out pipe: " << strerror(errno)
                          << "\n";
                if (rc)
                {
                    return -errno;
                }
                return -EIO;
            }

            cursor += egress;
        }
    }

    return rc;
}

/* Throws std::error_code on failure */
/* FIXME: Probably shouldn't do fallible stuff in a constructor */
NVMeBasicContext::NVMeBasicContext(boost::asio::io_service& io, int rootBus) :
    NVMeContext::NVMeContext(io, rootBus), io(io), reqStream(io), respStream(io)
{
    std::array<int, 2> responsePipe{};
    std::array<int, 2> requestPipe{};

    /* Set up inter-thread communication */
    if (::pipe(requestPipe.data()) == -1)
    {
        std::cerr << "Failed to create request pipe: " << strerror(errno)
                  << "\n";
        throw std::error_code(errno, std::system_category());
    }

    if (::pipe(responsePipe.data()) == -1)
    {
        std::cerr << "Failed to create response pipe: " << strerror(errno)
                  << "\n";

        if (::close(requestPipe[0]) == -1)
        {
            std::cerr << "Failed to close write fd of request pipe: "
                      << strerror(errno) << "\n";
        }

        if (::close(requestPipe[1]) == -1)
        {
            std::cerr << "Failed to close read fd of request pipe: "
                      << strerror(errno) << "\n";
        }

        throw std::error_code(errno, std::system_category());
    }

    reqStream.assign(requestPipe[1]);
    FileHandle streamIn(requestPipe[0]);
    FileHandle streamOut(responsePipe[1]);
    respStream.assign(responsePipe[0]);

    std::thread thread([streamIn{std::move(streamIn)},
                        streamOut{std::move(streamOut)}]() mutable {
        ssize_t rc = 0;

        if ((rc = processBasicQueryStream(streamIn, streamOut)) < 0)
        {
            std::cerr << "Failure while processing query stream: "
                      << strerror(static_cast<int>(-rc)) << "\n";
        }

        std::cerr << "Terminating basic query thread\n";
    });
    thread.detach();
}

void NVMeBasicContext::readAndProcessNVMeSensor(
    std::list<std::shared_ptr<NVMeSensor>>::iterator iter)
{
    if (iter == sensors.end())
    {
        this->pollNVMeDevices();
        return;
    }

    std::shared_ptr<NVMeSensor> sensor = *iter++;

    if (!sensor->readingStateGood())
    {
        sensor->markAvailable(false);
        sensor->updateValue(std::numeric_limits<double>::quiet_NaN());
        readAndProcessNVMeSensor(iter);
        return;
    }

    /* Potentially defer sampling the sensor sensor if it is in error */
    if (!sensor->sample())
    {
        readAndProcessNVMeSensor(iter);
        return;
    }

    auto command = encodeBasicQuery(sensor->bus);

    /* Issue the request */
    boost::asio::async_write(
        reqStream, boost::asio::buffer(command->data(), command->size()),
        [command](boost::system::error_code ec, std::size_t) {
            if (ec)
            {
                std::cerr << "Got error writing basic query: " << ec << "\n";
            }
        });

    auto response = std::make_shared<boost::asio::streambuf>();
    response->prepare(1);

    /* Gather the response and dispatch for parsing */
    boost::asio::async_read(
        respStream, *response,
        [response](const boost::system::error_code& ec, std::size_t n) {
            if (ec)
            {
                std::cerr << "Got error completing basic query: " << ec << "\n";
                return static_cast<std::size_t>(0);
            }

            /* 0. 确定下次接收的字节数为2(前两个字节表示数据流长度) */
            if (n == 0)
            {
                return static_cast<std::size_t>(2);
            }

            /* 1. 由前两个字节，确定下次接收的字节数(数据流长度) */
            static size_t len = 0;
            if (n == 2)
            {
                std::istream is(response.get());
                std::vector<char> lenData(2);
                is.read(lenData.data(), 2);
                len = static_cast<std::size_t>((lenData[1] << 8) + lenData[0]);
            }

            /* 2. 数据接收完毕时，返回0 */
            if (n > len + 2)
            {
                std::cerr << "Query stream has become unsynchronised: "
                          << "n: " << n << ", "
                          << "len: " << len << "\n";
                return static_cast<std::size_t>(0);
            }
            if (n == len + 2)
            {
                return static_cast<std::size_t>(0);
            }
            if (n > 2)
            {
                return len + 2 - n;
            }

            response->prepare(len);
            return len;
        },
        [self{shared_from_this()}, iter, sensor, response](
            const boost::system::error_code& ec, std::size_t length) mutable {
            if (ec)
            {
                std::cerr << "Got error reading basic query: " << ec << "\n";
                return;
            }

            if (length == 0)
            {
                std::cerr << "Invalid message length: " << length << "\n";
                return;
            }

            /* Deserialise the response */
            std::istream is(response.get());
            std::vector<char> data(response->size());
            is.read(data.data(), response->size());

            /* Update the sensor */
            self->processResponse(sensor, data.data(), data.size());

            /* Enqueue processing of the next sensor */
            self->readAndProcessNVMeSensor(iter);
        });
}

void NVMeBasicContext::pollNVMeDevices()
{
    auto scan = sensors.begin();

    scanTimer.expires_from_now(boost::posix_time::seconds(1));
    scanTimer.async_wait([self{shared_from_this()},
                          scan](const boost::system::error_code errorCode) {
        if (errorCode == boost::asio::error::operation_aborted)
        {
            return;
        }

        if (errorCode)
        {
            std::cerr << errorCode.message() << "\n";
            return;
        }

        self->readAndProcessNVMeSensor(scan);
    });
}

static double getTemperatureReading(int8_t reading)
{
    if (reading == static_cast<int8_t>(0x80) ||
        reading == static_cast<int8_t>(0x81))
    {
        // 0x80 = No temperature data or temperature data is more the 5 s
        // old 0x81 = Temperature sensor failure
        return std::numeric_limits<double>::quiet_NaN();
    }

    return reading;
}

void NVMeBasicContext::updateNVMeTemp(std::shared_ptr<NVMeSensor>& sensor,
                                      NVMeData* nvmeData)
{
    if ((nvmeData->statusFlags & NVME_MI_BASIC_SFLGS_DRIVE_NOT_READY) ||
        !(nvmeData->statusFlags & NVME_MI_BASIC_SFLGS_DRIVE_FUNCTIONAL))
    {
        sensor->markFunctional(false);
        return;
    }

    double value = getTemperatureReading(nvmeData->sensorValue);
    if (!std::isfinite(value))
    {
        sensor->incrementError();
        return;
    }

    sensor->updateValue(value);
}

void NVMeBasicContext::processResponse(std::shared_ptr<NVMeSensor>& sensor,
                                       void* msg, size_t len)
{
    std::array<uint8_t, basicCommand0Length> dataCommand0{};
    std::array<uint8_t, basicCommand8Length> dataCommand8{};
    std::array<uint8_t, basicCommand32Length> dataCommand32{};
    std::array<uint8_t, vpdCommandLength> dataVPD{};

    size_t basicTotalInfoLen =
        basicCommand0Length + basicCommand8Length + basicCommand32Length;

    /* 0. 校验入参合法性 */
    if (msg == nullptr || len < 6)
    {
        sensor->incrementError();
        return;
    }

    /* 1. 初始化NVMe参数 */
    if ((basicNVMeStateMaps[sensor->bus] == false) &&
        (vpdNVMeStateMaps[sensor->bus] == false))
    {
        initNVMeData(&nvmeDataMaps[sensor->bus]);
    }

    /* 2. 解析SMBus/I2C获取的NVMe信息，并赋值给NVMe结构体 */
    /* 3. 更新dbus上的静态信息 */
    uint8_t* messageData = static_cast<uint8_t*>(msg);
    std::string senname = "nvme" + std::to_string(getDeviceNum(sensor->name));

    if (len == basicCommand0Length)
    {
        memcpy(dataCommand0.data(), messageData, basicCommand0Length);
        parseNVMeBasicInfo(basicCommand0, dataCommand0.data(),
                           &nvmeDataMaps[sensor->bus]);
        allNVMeInfos[senname]->updateNVMeInfo(basicNVMeStateMaps[sensor->bus],
                                              vpdNVMeStateMaps[sensor->bus],
                                              &nvmeDataMaps[sensor->bus]);
    }
    else if (len == basicTotalInfoLen)
    {
        memcpy(dataCommand0.data(), messageData, basicCommand0Length);
        memcpy(dataCommand8.data(), messageData + basicCommand0Length,
               basicCommand8Length);
        memcpy(dataCommand32.data(),
               messageData + basicCommand0Length + basicCommand8Length,
               basicCommand32Length);

        parseNVMeBasicInfo(basicCommand0, dataCommand0.data(),
                           &nvmeDataMaps[sensor->bus]);
        parseNVMeBasicInfo(basicCommand8, dataCommand8.data(),
                           &nvmeDataMaps[sensor->bus]);
        parseNVMeBasicInfo(basicCommand32, dataCommand32.data(),
                           &nvmeDataMaps[sensor->bus]);

        allNVMeInfos[senname]->updateNVMeInfo(basicNVMeStateMaps[sensor->bus],
                                              vpdNVMeStateMaps[sensor->bus],
                                              &nvmeDataMaps[sensor->bus]);
        basicNVMeStateMaps[sensor->bus] = true;
    }
    else if (len == basicTotalInfoLen + vpdCommandLength)
    {
        memcpy(dataCommand0.data(), messageData, basicCommand0Length);
        memcpy(dataCommand8.data(), messageData + basicCommand0Length,
               basicCommand8Length);
        memcpy(dataCommand32.data(),
               messageData + basicCommand0Length + basicCommand8Length,
               basicCommand32Length);
        memcpy(dataVPD.data(),
               messageData + basicCommand0Length + basicCommand8Length +
                   basicCommand32Length,
               vpdCommandLength);

        parseNVMeBasicInfo(basicCommand0, dataCommand0.data(),
                           &nvmeDataMaps[sensor->bus]);
        parseNVMeBasicInfo(basicCommand8, dataCommand8.data(),
                           &nvmeDataMaps[sensor->bus]);
        parseNVMeBasicInfo(basicCommand32, dataCommand32.data(),
                           &nvmeDataMaps[sensor->bus]);
        parseNVMeVPDInfo(dataVPD.data(), &nvmeDataMaps[sensor->bus]);

        allNVMeInfos[senname]->updateNVMeInfo(basicNVMeStateMaps[sensor->bus],
                                              vpdNVMeStateMaps[sensor->bus],
                                              &nvmeDataMaps[sensor->bus]);
        basicNVMeStateMaps[sensor->bus] = true;
        vpdNVMeStateMaps[sensor->bus] = true;
    }
    else
    {
        return;
    }

    /* 4. 更新Dbus上的温度值 */
    updateNVMeTemp(sensor, &nvmeDataMaps[sensor->bus]);

    /* 5. 更新dbus上的状态信息 */
    allNVMeStatus[senname]->updateNVMeStatus(&nvmeDataMaps[sensor->bus]);
}
